#include "rsa_crypt.h"

#include <error.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

#include "debug.h"

RSA *rsa_generate_key(void)
{
    RSA *r;
    BIGNUM *e;
    void *ret = NULL;

    e = BN_new();
    if(!e)
    {
        PRINTF("BN_new error code:%08lx\r\n",ERR_get_error());
        return ret;
    }
    BN_init(e);
    //设置加密指数
    BN_set_word(e,RSA_F4);
    r = RSA_new();
    if(!r)
    {
        PRINTF("RSA_new error code:%08lx\r\n",ERR_get_error());
        goto bn_free;
    }
    //生成密钥对
    if(RSA_generate_key_ex(r,2048,e,NULL) <= 0)
    {
        PRINTF("RSA_generate_key_ex error code:%08lx\r\n",ERR_get_error());
        goto bn_free;
    }

    ret = r;
bn_free:
    BN_clear_free(e);

    return ret;
}

int rsa_save_public_to_file(RSA *r,const char *filename)
{
    int ret = -1;
    FILE *fp;

    fp = fopen(filename,"w");
    if(!fp)
    {
        perror("fopen ");
        return ret;
    }
    ret = PEM_write_RSA_PUBKEY(fp,r);
    if(ret != 1)
    {
        PRINTF("PEM_write_RSA_PUBKEY error code:%08lx\r\n",ERR_get_error());
        goto j_fclose;
    }

    ret = 1;

j_fclose:
    fclose(fp);

    return ret;
}

RSA *rsa_get_public_from_file(const char *filename)
{
    void *ret = NULL;
    FILE *fp;
    RSA *key;

    fp = fopen(filename,"r");
    if(!fp)
    {
        perror("fopen ");
        return ret;
    }
    key = PEM_read_RSA_PUBKEY(fp,NULL,NULL,NULL);
    if(!key)
    {
        PRINTF("PEM_read_PUBKEY error code:%08lx\r\n",ERR_get_error());
        goto j_fclose;
    }

    ret = key;

j_fclose:
    fclose(fp);

    return ret;
}

int rsa_save_private_to_file(RSA *r,const char *filename,void *u)
{
    int ret = -1;
    FILE *fp;
    void *crypt = NULL;

    fp = fopen(filename,"w");
    if(!fp)
    {
        perror("fopen ");
        return ret;
    }
    if(u)
    {
        crypt = (void *)EVP_des_ede3_cbc();
    }
    ret = PEM_write_RSAPrivateKey(fp,r,(const EVP_CIPHER *)crypt,NULL,0,NULL,u);
    if(ret != 1)
    {
        PRINTF("PEM_write_RSAPrivateKey error code:%08lx\r\n",ERR_get_error());
        goto j_fclose;
    }

    ret = 1;

j_fclose:
    fclose(fp);

    return ret;
}

RSA * rsa_get_private_from_file(const char *filename,void *u)
{
    void *ret = NULL;
    FILE *fp;
    RSA *key;

    fp = fopen(filename,"r");
    if(!fp)
    {
        perror("fopen ");
        return ret;
    }
    key = PEM_read_RSAPrivateKey(fp,NULL,NULL,u);
    if(!key)
    {
        PRINTF("PEM_read_RSAPrivateKey error code:%08lx\r\n",ERR_get_error());
        goto j_fclose;
    }

    ret = key;

j_fclose:
    fclose(fp);

    return ret;
}

RSA * rsa_get_public_from_mem(const void *buf,int len)
{
    void *ret = NULL;
    RSA *key;
    BIO *bp;

    bp = BIO_new_mem_buf(buf,len);
    if(!bp)
    {
        PRINTF("BIO_new_mem_buf error code:%08lx\r\n",ERR_get_error());
        return NULL;
    }
    key = PEM_read_bio_RSA_PUBKEY(bp,NULL,NULL,NULL);
    if(!key)
    {
        PRINTF("PEM_read_bio_RSA_PUBKEY error code:%08lx\r\n",ERR_get_error());
        goto j_free;
    }

    ret = key;

j_free:
    BIO_free_all(bp);

    return ret;
}

RSA * rsa_get_private_from_mem(const void *buf,int len,void *u)
{
    void *ret = NULL;
    RSA *key;
    BIO *bp;

    bp = BIO_new_mem_buf(buf,len);
    if(!bp)
    {
        PRINTF("BIO_new_mem_buf error code:%08lx\r\n",ERR_get_error());
        return NULL;
    }
    key = PEM_read_bio_RSAPrivateKey(bp,NULL,NULL,u);
    if(!key)
    {
        PRINTF("PEM_read_bio_RSAPrivateKey error code:%08lx\r\n",ERR_get_error());
        goto j_free;
    }

    ret = key;

j_free:
    BIO_free_all(bp);

    return ret;
}

int rsa_public_encrypt(const unsigned char *plaintext,int palintext_len,RSA *r,unsigned char *ciphertext)
{
    //公钥加密
    return RSA_public_encrypt(palintext_len,plaintext,ciphertext,r,RSA_PKCS1_OAEP_PADDING);
}

int rsa_private_decrypt(const unsigned char *ciphertext,RSA *r,unsigned char *plaintext)
{
    //私钥解密
    return RSA_private_decrypt(RSA_size(r),ciphertext,plaintext,r,RSA_PKCS1_OAEP_PADDING);
}

int rsa_private_encrypt(const unsigned char *plaintext,int palintext_len,RSA *r,unsigned char *ciphertext)
{
    //私钥加密
    return RSA_private_encrypt(palintext_len,plaintext,ciphertext,r,RSA_PKCS1_PADDING);
}

int rsa_public_decrypt(const unsigned char *ciphertext,RSA *r,unsigned char *plaintext)
{
    //公钥解密
    return RSA_public_decrypt(RSA_size(r),ciphertext,plaintext,r,RSA_PKCS1_PADDING);
}

int rsa_sign(RSA *r,const unsigned char *d,size_t n,unsigned char *sigret,unsigned int *siglen)
{
    unsigned char md[16];

    memset(md,0,sizeof(md));
    //对数据进行摘要
    MD5((const unsigned char *)d,n,md);
    //对摘要进行签名
    return RSA_sign(NID_md5,md,sizeof(md),sigret,siglen,r);
}

int rsa_verify(RSA *r,const unsigned char *d,size_t n,unsigned char *sigret,unsigned int siglen)
{
    unsigned char md[16];

    //对数据进行摘要
    MD5((const unsigned char *)d,n,md);
    //对数据进行验签
    return RSA_verify(NID_md5,md,sizeof(md),sigret,siglen,r);
}
